昨天用一間真實店家測試 Places API,讓店名、地址與座標出現在地圖和卡片上。不過,插座多不多、環境安不安靜,這些工作條件仍是未知。
今天回到首頁,測試已經做好的篩選器:點下「插座多」後,哪些店會留下來?再加上「不限時」,地圖和列表會不會一起更新?
這次沿用 Firestore 裡的示範資料,方便逐筆核對結果。昨天查到的 Places 資料仍留在單店測試頁,尚未匯入首頁。
「有插座」可能只有一兩個座位能用,不能直接歸進「插座多」。同樣地,店家若只在平日不限時,也不能一律通過「不限時」篩選。
目前首頁有五個條件:
| 篩選條件 | 通過條件 | 不納入的情況 |
|---|---|---|
| 插座多 | work.powerOutlet.value = many | limited、none、unknown |
| 不限時 | work.timeLimitType.value = none | conditional、always、unknown |
| 安靜 | work.noiseLevel.value = quiet | normal、loud、unknown |
| 營業中 | business.status = open | closed、unknown |
| Wi-Fi 穩定 | wifiAvailable.value = yes,且 wifiStability.value = stable | 只有 Wi-Fi,但穩定度未知,也不通過 |
沒有開啟篩選時,資料未知的店仍會出現在列表。選了條件後,只留下明確符合的店;缺少資料的店暫時不納入,但也不因此把它標成「沒有插座」或「不安靜」。
這次的「營業中」也是用示範狀態測試。之後將真實營業資訊接進首頁時,還要確認來源與更新方式,避免一直拿舊狀態判斷。
首頁已經有篩選按鈕(Filter Chips)、地圖標記連動和零結果畫面。我先請 Agent 對照規格,找出還需要修正的地方。
請檢查現有 Laravel+Inertia+React 專案的首頁篩選功能。
先讀 docs/ 的 CURRENT 規格、README 與 package.json,
再檢查 Home.tsx、FilterChips.tsx、GoogleMapView.tsx、
CafeCard.tsx、EmptyState.tsx、店家型別與 Firestore 讀取流程。
檔案若已更名,找出對應實作。
目前首頁由 Laravel 讀取 Firestore,再透過 Inertia 傳入 cafes。
另有獨立的 Places 單店測試頁,不把其結果混入首頁。
mockCafes.ts 只作為原始示範資料參考,不能取代實際傳入的 cafes。
先檢查並列計畫,不修改檔案:
1. 五個 Filter 是否依 DATA_FIELDS.md 的明確值判斷:
插座多 = powerOutlet.value 為 many;
不限時 = timeLimitType.value 為 none;
安靜 = noiseLevel.value 為 quiet;
營業中 = business.status 為 open;
Wi-Fi 穩定 = wifiAvailable.value 為 yes 且 wifiStability.value 為 stable。
2. 多條件與搜尋是否同時採 AND,unknown 不當作符合。
3. 地圖與列表是否共用 filteredCafes;
無有效座標的店可留在列表,但不建立 Marker。
4. 選取的店被排除後是否清除選取,取消條件後是否不會恢復舊選取。
5. 清除篩選是否保留搜尋字串,清除搜尋是否保留已選條件。
6. 篩選零結果、資料庫空資料與讀取失敗是否分開呈現。
7. Inertia 傳入新的 cafes 後,即使搜尋與條件沒變,
篩選結果是否仍會重算;特別檢查 useMemo 的依賴。
8. 手機上 Chip 是否能橫向捲動,選取狀態與 aria-pressed 是否一致。
9. 頁尾與資料來源標示是否符合目前 Firestore+Google Maps 的實作,
不沿用「未串接地圖、登入、資料庫」的舊說明。
列出已符合、需修正與未驗證項目,以及必要修改檔案。
依實際首頁資料提出單一條件、多條件及零結果的測試組合。
若只能讀到原始 mock 檔,請明確註記,不能宣稱已核對 Firestore。
不呼叫付費 Places API、不修改雲端資料、不自動 commit 或 push。
列完計畫後先停下。
看完計畫,確認修改範圍後,再送出實作指令。如果檢查沒有發現問題,就直接進入後面的畫面測試。
依照剛才確認的計畫,修正現有首頁篩選功能的必要問題。
已符合的功能保留,不重做首頁、不改 UI 設計或五個篩選條件的定義。
讓搜尋、篩選與新的 cafes 資料都能觸發結果更新。
地圖和列表共用同一份結果;只有有效座標才建立 Marker。
選取店家被排除後清除選取,取消條件時不自動選回舊店家。
保留清除搜尋與重設篩選各自的行為,
並區分篩選零結果、來源空資料與載入失敗。
必要時修正仍描述舊資料流程的文字,保留示範資料標示。
不把 Places 單店結果加入首頁,不修改 Firestore 文件,
不呼叫付費 Places API,不新增 AI、排序、即時監聽或新篩選器。
針對實際修改的邏輯執行必要測試,再執行:
npm run typecheck
npm run build
最後列出修改檔案、檢查結果、瀏覽器驗證方式與未驗證事項。
沒有執行的檢查不要列成通過;不自動 commit 或 push。
Agent 完成必要修正與程式檢查後,再開啟首頁 / 測試。先清空搜尋並取消所有條件,記下原本的店家數量,再點「插座多」。
這時應只留下 work.powerOutlet.value 為 many 的店。以原始示範資料來說,Ruins 和未央符合條件;Fika 是 limited,代表部分座位有插座,因此不會留下來。
地圖和列表要對應同一批店家。不過,缺少有效座標的店只會出現在列表,所以卡片數不一定等於地圖標記數。核對時要看是哪幾間店,而不只是數量。
📸 圖片 1-1|尚未篩選的首頁
📸 圖片 1-2|開啟「插座多」
接著保留「插座多」,再加上「不限時」。
多選採用 AND,也就是每個已選條件都要符合。在資料與搜尋文字不變的情況下,多加一個條件,結果只會減少或維持原數量。
以原始五間示範資料來看,Ruins 的時間規則是 conditional,Fika 的插座數量是 limited,因此這個組合只會留下未央。若 Firestore 的資料已經調整,則以目前欄位值為準。
搜尋也會一起計算:輸入店名或地址後,店家必須同時符合關鍵字和已選條件。這部分留到最後分開測試,先沿用目前的兩個條件,看看零結果會怎麼呈現。
📸 圖片 2|「插座多」與「不限時」同時啟用
沿用剛才的兩個條件,再加上「營業中」。
原始示範資料中的未央是 closed,因此這組條件預期得到零結果。此時列表應顯示「無符合條件的咖啡廳」,地圖也不應殘留被排除的店家標記。
「篩選後沒有符合的店」、「資料庫還沒有店家」和「Firestore 讀取失敗」,需要各自的提示。這樣使用者才知道,現在可以調整條件,還是要等資料載入。
接著測試清除按鈕:
剛才測試時搜尋欄是空的,所以按下「重設所有篩選」後,應恢復原本的列表。若搜尋欄還有文字,結果就會繼續受關鍵字限制。
📸 圖片 3|零結果與重設篩選
完成零結果測試後,先清空搜尋、取消所有條件,再補測以下幾項:
yes 和 stable;只有提供 Wi-Fi、穩定度仍是 unknown 的店不通過。如果 Firestore 的內容已經改過,就選一間能被目前條件排除的店來測。
| 檢查 | 預期結果 |
|---|---|
| 五個條件各自開啟 | 依欄位明確值判斷,unknown 不通過 |
| 同時開啟多個條件 | 所有條件都符合才保留 |
| 搜尋搭配篩選 | 同時符合關鍵字與已選條件 |
| 無座標店家 | 可留在列表,不建立假位置的 Marker |
| 選取店家被排除 | 清除選取;取消條件後不自動選回 |
| 零結果後重設篩選 | Chips 取消,結果依剩餘搜尋條件重算 |
| 清空搜尋文字 | 搜尋取消,已選 Chips 保留 |
| 原始資料更新 | 條件不變時,結果仍依新的 cafes 重算 |
| 資料空白或讀取失敗 | 分別呈現,不冒充篩選零結果 |
昨天接 Places 時,沒有取得的工作條件保留了未知。今天測篩選器,則要確認這些未知值不會被當成符合條件。
點下「插座多」後留下哪些店,再加上「不限時」會排除誰,每一步都能對回欄位。之後換成查核過的資料,也能用同一套規則繼續檢查。